package com.project.srtp.secure.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.srtp.secure.dao.entity.ComplianceRuleDO;
import com.project.srtp.secure.dao.mapper.ComplianceRuleMapper;
import com.project.srtp.secure.dto.req.CheckRuleASTNodeReqDTO;
import com.project.srtp.secure.dto.req.ComplianceRuleReqDTO;
import com.project.srtp.secure.dto.resp.AstNodeRespDto;
import com.project.srtp.secure.dto.resp.RulesRespDTO;
import com.project.srtp.secure.service.ComplianceService;
import com.project.srtp.secure.util.FeelAstUtil;
import lombok.RequiredArgsConstructor;
import org.kie.dmn.feel.lang.ast.ASTNode;
import org.kie.dmn.feel.lang.ast.BaseNode;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author 曹行阳
 * @version 0.1
 * @date 2025/6/11 11:20
 */
@Service
@RequiredArgsConstructor
public class ComplianceServiceImpl extends ServiceImpl<ComplianceRuleMapper, ComplianceRuleDO> implements ComplianceService {
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional
    public void createRule(ComplianceRuleReqDTO reqDTO) {
        validateFeelExpression(reqDTO.getFeelExpression());

        // 查询是否已有相同规则名存在
        LambdaQueryWrapper<ComplianceRuleDO> queryWrapper = Wrappers.lambdaQuery(ComplianceRuleDO.class)
                .eq(ComplianceRuleDO::getRuleName, reqDTO.getRuleName());

        ComplianceRuleDO existingRule = baseMapper.selectOne(queryWrapper);

        ComplianceRuleDO rule = ComplianceRuleDO.builder()
                .ruleName(reqDTO.getRuleName())
                .description(reqDTO.getDescription())
                .feelExpression(reqDTO.getFeelExpression())
                .Active(true)
                .updatedAt(Instant.now())
                .build();

        if (existingRule != null) {
            // 若已存在，更新字段（保留原创建时间）
            rule.setId(existingRule.getId());
            rule.setCreatedAt(existingRule.getCreatedAt());
            boolean success = this.updateById(rule);
            if (!success) {
                throw new RuntimeException("规则更新失败");
            }
        } else {
            // 不存在，插入新规则
            rule.setCreatedAt(Instant.now());
            boolean success = this.save(rule);
            if (!success) {
                throw new RuntimeException("规则插入失败");
            }
        }
    }

    private void validateFeelExpression(String feelExpression) {
        try {
            BaseNode ast = FeelAstUtil.parseExpression(feelExpression);
            if (ast == null) {
                throw new IllegalArgumentException("FEEL表达式解析结果为空");
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("FEEL表达式格式错误: " + e.getMessage(), e);
        }
    }


    @Override
    public AstNodeRespDto checkRuleASTNode(CheckRuleASTNodeReqDTO request) {
        BaseNode rootNode;
        try {
            rootNode = FeelAstUtil.parseExpression(request.getFeelExpression());
        } catch (Exception e) {
            throw new IllegalArgumentException("FEEL表达式解析错误: " + e.getMessage(), e);
        }
        return convertBaseNodeToAstNodeRespDto(rootNode);
    }

    @Override
    public List<RulesRespDTO> getAllRules() {
        LambdaQueryWrapper<ComplianceRuleDO> queryWrapper = Wrappers.lambdaQuery(ComplianceRuleDO.class)
                .orderByDesc(ComplianceRuleDO::getId);
        List<RulesRespDTO> resp = new ArrayList<>();
        List<ComplianceRuleDO> complianceRuleDOS = baseMapper.selectList(queryWrapper);
        for (ComplianceRuleDO ruleDO : complianceRuleDOS) {
            RulesRespDTO rulesRespDTO = new RulesRespDTO();
            rulesRespDTO.setRuleName(ruleDO.getRuleName());
            rulesRespDTO.setFeelExpression(ruleDO.getFeelExpression());
            rulesRespDTO.setDescription(ruleDO.getDescription());
            resp.add(rulesRespDTO);
        }
        return resp;
    }

    private AstNodeRespDto convertBaseNodeToAstNodeRespDto(BaseNode node) {
        if (node == null) {
            return null;
        }
        AstNodeRespDto dto = new AstNodeRespDto();
        dto.setNodeType(node.getClass().getSimpleName());
        dto.setText(node.getText());

        ASTNode[] children = node.getChildrenNode();
        if (children != null && children.length != 0) {
            List<AstNodeRespDto> childDtos = new ArrayList<>();
            for (ASTNode child : children) {
                AstNodeRespDto childDto = convertBaseNodeToAstNodeRespDto((BaseNode) child);
                if (childDto != null) {
                    childDtos.add(childDto);
                }
            }
            dto.setChildren(childDtos);
        } else {
            dto.setChildren(Collections.emptyList());
        }
        return dto;
    }

    private boolean isViolationState(ComplianceRuleDO rule, String state) {
        // 从Redis获取违规状态集
        return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(
                "compliance:rule:" + rule.getId() + ":violations", state));
    }
}
